package com.springcloudalibaba.apiAdmin.controller;

import com.springcloudalibaba.baseredis.service.RedissonSingleService;
import com.springcloudalibaba.bclass.base.BaseResult;
import com.springcloudalibaba.bclass.util.LoggerUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.concurrent.TimeUnit;

/**
 * @描述：测试
 * @作者：lixing_java@163.com
 * @时间：2021/9/17 14:26
 */
@RestController
@RequestMapping("demo")
public class DemoController {
    /**
     * @描述 测试
     * @作者 lixing_java@163.com
     * @日期 2021/9/17 14:29
     * 直接访问：127.0.0.1:8770/apiAdmin/demo/showHelloWorld
     * 网关访问：127.0.0.1:8763/springCloudGateway/gatewayAdmin/demo/showHelloWorld
     */
    @GetMapping("showHelloWorld")
    public BaseResult<String> showHelloWorld() {
        return new BaseResult<String>().success("apiAdmin-HelloWorld");
    }

    @Resource
    private RedissonSingleService redissonSingleService;
    @Resource
    private RedissonClient redissonClient;
    /**
     * @描述 测试
     * @作者 lixing_java@163.com
     * @日期 2021/9/17 14:29
     * 直接访问：127.0.0.1:8770/apiAdmin/demo/reentrantLock
     * 网关访问：127.0.0.1:8763/springCloudGateway/gatewayAdmin/demo/reentrantLock
     */
    @GetMapping("reentrantLock")
    public BaseResult<String> reentrantLock() {
        RLock rLock = redissonClient.getLock("rLock");
        boolean res = false;
        try {
            /*
             * 1、如果需要使用续锁功能，请不要设置锁的过期时间（可以设置成-1），否则RedissonLock就会认为你需要自己控制锁时间而放弃执行续锁逻辑
             * 2、RedissonLock的续锁逻辑是用netty下的Timeout定时器来实现的，默认锁时间是30秒，定时器每锁时间/3也就是10秒执行一次。来判断是否还持有锁，如果还持有锁就重置锁时间为30秒。从而避免业务执行时间大于锁时间而导致的锁被释放了的问题
             */
            // 尝试取锁：
            // 1、取锁超时时间 500 毫秒，超过则取锁失败
            // 2、取锁成功后，-1表示锁使用默认的有效期30秒（如果业务提前执行完毕也会提前释放锁），每隔30/3（10）秒会自动检测锁是否存在，存在则重置锁的有效期为 30 秒
            res = rLock.tryLock(500, -1, TimeUnit.MILLISECONDS);
            if (res) {
                LoggerUtil.info(MessageFormat.format("{0} 拿到锁，开始执行任务", Thread.currentThread().getName()));
                Thread.sleep(150000); // 休眠N秒，模拟业务执行时间
                LoggerUtil.info(MessageFormat.format("{0} 拿到锁，执行任务成功", Thread.currentThread().getName()));
                return new BaseResult<String>().success(MessageFormat.format("{0} 拿到锁，执行任务成功", Thread.currentThread().getName()));
            } else {
                LoggerUtil.info(MessageFormat.format("{0} 取锁超市", Thread.currentThread().getName()));
                return new BaseResult<String>().success(MessageFormat.format("{0} 取锁超时", Thread.currentThread().getName()));
            }
        } catch (InterruptedException e) {
            LoggerUtil.error(MessageFormat.format("{0} 系统错误：{1}", Thread.currentThread().getName(), e.getMessage()));
            return new BaseResult<String>().fail(MessageFormat.format("{0} 系统错误：{1}", Thread.currentThread().getName(), e.getMessage()));
        } finally {
            if(rLock.isLocked() && rLock.isHeldByCurrentThread()) {
                // 释放锁
                LoggerUtil.info(MessageFormat.format("{0} 释放锁", Thread.currentThread().getName()));
                rLock.unlock();
            }
        }
    }
}
